using System;
using System.Linq;
using System.Windows;
using SalesPoint.Services;
using SalesPoint.ViewModels;
using SalesPoint.Views;
using SalesPoint.Security;
using Xtensive.Orm;
using Xtensive.Orm.Security;

namespace SalesPoint
{
  public class SalesPointApp : Application
  {
    private delegate void UpdateMessageDelegate(string message);

    public static Domain Domain { get; private set; }

    public static Session Session { get; private set; }

    public static ImpersonationContext ImpersonationContext { get; private set; }

    [STAThread]
    private static void Main()
    {
      new SalesPointApp();
    }

    #region Initialization

    protected override void OnStartup(StartupEventArgs e)
    {
      base.OnStartup(e);
      var service = new InitializationService();
      service.ProgressChanged += OnServiceProgressChanged;
      service.Completed += OnServiceCompleted;
      service.Run();
    }

    private static void OnServiceProgressChanged(object sender, InitializationProgressChangedEventArgs e)
    {
      if (Current.MainWindow == null)
        return;
      var dispatcher = Current.MainWindow.Dispatcher;
      var updateMessage = new UpdateMessageDelegate(UpdateMessage);
      dispatcher.Invoke(updateMessage, e.Progress);
    }

    private static void UpdateMessage(string message)
    {
      var mainWindow = Current.MainWindow as SplashScreenView;
      if (mainWindow != null)
        mainWindow.UpdateMessage(message);
    }

    private static void OnServiceCompleted(object sender, InitializationCompletedEventArgs e)
    {
      var splash = Current.MainWindow;
      if (e.Exception != null) {
        MessageBox.Show(e.Exception.Message, "Initialization error", MessageBoxButton.OK, MessageBoxImage.Error);
        splash.Close();
        return;
      }
      Domain = e.Domain;
      Session = Domain.OpenSession();

      // Login phase
      ShowLoginScreen();
    }

    private static void ShowLoginScreen()
    {
      var current = Current.MainWindow;
      var loginScreen = new LoginView();
      var loginViewModel = new LoginViewModel(Session);
      loginViewModel.SuccessfulLogin += OnSuccessfulLogin;
      loginScreen.DataContext = loginViewModel;

      Current.MainWindow = loginScreen;
      Current.MainWindow.Show();
      current.Close();
    }

    static void OnSuccessfulLogin(object sender, LoginEventArgs e)
    {
      var loginScreen = Current.MainWindow;
      ImpersonationContext = Session.Impersonate(e.Principal);

      var mainScreen = new MainWindow();
      var dataContext = new MainWindowViewModel(Session);
      dataContext.Logout += OnLogout;
      mainScreen.DataContext = dataContext;
      Current.MainWindow = mainScreen;
      Current.MainWindow.Show();
      loginScreen.Close();
    }

    #endregion

    static void OnLogout(object sender, EventArgs e)
    {
      ImpersonationContext.Undo();
      ShowLoginScreen();
    }

    public SalesPointApp()
    {
      StartupUri = new Uri("Views/SplashScreenView.xaml", UriKind.Relative);
      Run();
    }
  }
}